package com.inspur.icity.bus.base.core.service;

import com.inspur.icity.bus.base.core.model.UserSessionInfo;
import com.inspur.icity.bus.base.core.util.JacksonUtil;
import net.spy.memcached.AddrUtil;
import net.spy.memcached.ConnectionFactoryBuilder;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.auth.AuthDescriptor;
import net.spy.memcached.auth.PlainCallbackHandler;
import net.spy.memcached.internal.OperationFuture;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.Properties;
import java.util.concurrent.ExecutionException;

/**
 * Ocs Service 阿里云缓存服务
 */
public class OcsService {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    public static final int EXPIRE_TIME = 1800; // Second
    private static final String SYSTEM_PROPERTY_MEMCACHED_PROPERTIES_FILENAME = "memcached.properties.filename";
    private static final String MEMCACHED_RESOURCE = "memcached.properties";

    // 清空缓存地址
    public static final String FLUSH_CACHE_URL_PRO = "https://appapi.yigaosu.com/v2/cache/flush"; // 生产环境
    public static final String FLUSH_CACHE_URL_DEV = "http://115.28.104.19:8080/v2/cache/flush"; // 测试环境

    private MemcachedClient cache = null;

    /**
     * Constructor
     */
    public OcsService() {
        init();
    }

    /**
     * Init Ocs Cache From Config
     */
    private void init() {
        logger.info("OcsService 开始初始化...");
        // 1. Load the properties specified from /memcached.properties, if present
        String memcachedPropertiesFilename = System.getProperty(SYSTEM_PROPERTY_MEMCACHED_PROPERTIES_FILENAME, MEMCACHED_RESOURCE);
        Properties config = new Properties();
        InputStream input = getClass().getClassLoader().getResourceAsStream(memcachedPropertiesFilename);
        if (input != null) {
            try {
                config.load(input);
            } catch (IOException e) {
                throw new RuntimeException("An error occurred while reading classpath property '"
                        + memcachedPropertiesFilename
                        + "', see nested exceptions", e);
            } finally {
                try {
                    input.close();
                } catch (IOException e) {
                    // close quietly
                }
            }
        }
        String userName = config.getProperty("org.mybatis.caches.memcached.username");
        String password = config.getProperty("org.mybatis.caches.memcached.password");
        String serverUrl = config.getProperty("org.mybatis.caches.memcached.servers");
        // 2. New a cache
        try {
            AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, new PlainCallbackHandler(userName, password));
            cache = new MemcachedClient(new ConnectionFactoryBuilder().setProtocol(ConnectionFactoryBuilder.Protocol.BINARY).setAuthDescriptor(ad).build(), AddrUtil.getAddresses(serverUrl));
            logger.info("OCS缓存连接成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("OcsService 初始化结束！");
    }

    /**
     * Set Object
     */
    public boolean set(String key, String value) {
        boolean result = false;
        if (cache != null) {
            OperationFuture<Boolean> future = cache.set(key, EXPIRE_TIME, value);
            logger.info("[OcsService.set] KEY = " + key + ", VALUE = " + value);
            try {
                result = future.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        logger.info("[OcsService.set] RESULT = " + result);
        return result;
    }

    /**
     * Get Object
     */
    public Object get(String key) {
        if (cache != null) {
            Object value = cache.get(key);
            logger.info("[OcsService.get] KEY = " + key + ", VALUE = " + value);
            return value;
        }
        return null;
    }

    /**
     * Delete Object
     */
    public boolean delete(String key) {
        boolean result = false;
        if (cache != null) {
            OperationFuture<Boolean> future = cache.delete(key);
            logger.info("[OcsService.delete] KEY = " + key);
            try {
                result = future.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        logger.info("[OcsService.delete] RESULT = " + result);
        return result;
    }

    /**
     * Close Ocs Cache
     */
    public void shutdown() {
        if (cache != null) {
            cache.shutdown();
        }
    }

    /**
     * Put UserSessionInfo into OCS
     * @return
     */
    public boolean putUserSessionInfo(String sessionId, UserSessionInfo usi) {
        if (StringUtils.isEmpty(sessionId) || usi == null) {
            return false;
        }
        // Put into OCS
        return set(sessionId, usi.toJson());
    }

    /**
     * Get UserSessionInfo from OCS
     * @return
     */
    public UserSessionInfo getUserSessionInfo(String sessionId) {
        if (StringUtils.isEmpty(sessionId)) {
            return null;
        }
        Object value = get(sessionId);
        if (value != null) {
            return JacksonUtil.readValue(value.toString(), UserSessionInfo.class);
        }
        return null;
    }

    /**
     * Delete UserSessionInfo from OCS
     * @return
     */
    public boolean deleteUserSessionInfo(String sessionId) {
        if (StringUtils.isEmpty(sessionId)) {
            return false;
        }
        return delete(sessionId);
    }

    /**
     * Flush Ocs Cache
     * @return
     */
    public void flush() {
        cache.flush();
    }

    /**
     * 清空生产环境缓存
     * @return
     */
    public boolean flushProCache() {
        return flushCache(FLUSH_CACHE_URL_PRO);
    }

    /**
     * 清空测试环境缓存
     * @return
     */
    public boolean flushDevCache() {
        return flushCache(FLUSH_CACHE_URL_DEV);
    }

    /**
     * Flush Cache
     * @param url
     * @return
     */
    private boolean flushCache(String url) {
        boolean result = false;
        RequestConfig config = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
        try (CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build()) {
            HttpGet httpGet1 = new HttpGet(url);
            httpGet1.addHeader("accept", "application/json");
            httpGet1.addHeader("team", "egaosu");
            httpGet1.addHeader("access_token", "09cdae58-0ecf-4e56-8dae-580ecf8e56ce");

            CloseableHttpResponse response = httpClient.execute(httpGet1);
            logger.debug("[Request]" + url);
            if (response.getStatusLine().getStatusCode() != 200) {
                throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode());
            }
            StringWriter writer = new StringWriter();
            IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
            logger.debug("[Response]" + writer.toString());
            if ("ok".equals(writer.toString())) {
                result = true;
            }
        } catch (IOException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        }
        return result;
    }
}
